﻿using System;
using System.Net;
using System.Net.Sockets;
using CSEngine;

namespace Server
{
    class GameData
    {
        public enum GameType { LOCAL, REMOTE, INVALID };

        private GameSettings settings;
        private Move? remoteMove;
        protected AI ai;
        protected bool in_progress;
        private NetworkStream remoteStream;
        private bool display;
        private GameType type;
        private bool toggleDisplay;

        public GameData()
        {
            settings = GameSettings.Default;
            remoteMove = null;
            ai = GameServer.GetDefaultAI();
            remoteStream = null;
            display = true;
            in_progress = false;
            type = GameType.INVALID;
            toggleDisplay = false;
        }

        public GameData(AI myAI)
        {
            settings = GameSettings.Default;
            in_progress = false;
            remoteStream = null;
            remoteMove = null;
            ai = myAI;
            display = true;
            type = GameType.INVALID;
            toggleDisplay = false;
        }

        protected GameData(GameType ty, NetworkStream str)
        {
            settings = GameSettings.Default;
            in_progress = false;
            ai = GameServer.GetDefaultAI();
            remoteStream = str;
            remoteMove = null;
            display = true;
            type = ty;
            toggleDisplay = false;
        }

        protected GameData(GameType ty, NetworkStream str, AI myAI)
        {
            settings = GameSettings.Default;
            in_progress = false;
            ai = myAI;
            remoteStream = str;
            remoteMove = null;
            display = true;
            type = ty;
            toggleDisplay = false;
        }

        // This method should ONLY be called by the Game thread!
        protected Move WaitForRemoteMove(object sender, PlayerTurnArgs e)
        {
            Move result;
            RemoteMove = null;

            // Wait for remoteMove to be updated by the server thread
            while (!RemoteMove.HasValue)
                System.Threading.Thread.Sleep(Settings.InputDelay);

            result = RemoteMove.GetValueOrDefault();
            RemoteMove = null;
            return result;
        }

        protected void NotifyGameOver(object sender, GameOverArgs e)
        {
            string msg = "Game Over - ";
            if (e.Draw)
                msg += "Draw";
            else
                msg += e.Winner.Name + " Wins";

            if (Display)
            {
                Console.WriteLine(msg);
            }

            TcpServer.SendLine(RemoteStream, msg);
        }

        protected void NotifyIllegal(object sender, EventArgs e)
        {
            TcpServer.SendLine(RemoteStream, "ILLEGAL");
        }
        
        protected void DisplayEveryOther(object sender, BoardUpdatedArgs e)
        {
            Console.WriteLine(e.Board.ToString());
            if (Display && toggleDisplay)
                TcpServer.SendLine(RemoteStream, e.Board.ToString().Replace("\n", "\r\n"));

            toggleDisplay = !toggleDisplay;
        }

        protected void DisplayBoard(object sender, BoardUpdatedArgs e)
        {
            if (Display)
            {
                Console.WriteLine(e.Board.ToString());
                TcpServer.SendLine(RemoteStream, e.Board.ToString().Replace("\n", "\r\n"));
            }
        }

        public GameSettings Settings
        {
            get { return settings; }
            set { settings = value; }
        }

        public bool InProgress
        {
            get { return in_progress; }
        }

        public GameType Type
        {
            get { return type; }
        }

        public bool Display
        {
            get { return display; }
            set { display = value; }
        }

        public Move? RemoteMove
        {
            get { return remoteMove; }
            set { remoteMove = value; }
        }

        public virtual AI AI
        {
            get { return ai; }
            set { ai = value; }
        }

        public NetworkStream RemoteStream
        {
            get { return remoteStream; }
        }
    };
}
